package com.easychat.service.impl;

import com.easychat.common.LeaseException;
import com.easychat.common.PageResult;
import com.easychat.dto.GroupInfoDto;
import com.easychat.dto.MessageSendDto;
import com.easychat.dto.SysSettingDto;
import com.easychat.dto.TokenUserInfoDto;
import com.easychat.entity.*;
import com.easychat.entity.config.AppConfig;
import com.easychat.entity.constants.Constants;
import com.easychat.entity.query.GroupInfoQuery;
import com.easychat.entity.query.UserContactQuery;
import com.easychat.enums.*;
import com.easychat.mappers.*;
import com.easychat.redis.RedisComponent;
import com.easychat.service.GroupInfoService;
import com.easychat.service.UserContactApplyService;
import com.easychat.service.UserContactService;
import com.easychat.service.UserInfoService;
import com.easychat.utils.StringTools;
import com.easychat.websocket.ChannelContextUtils;
import com.easychat.websocket.MessageHandler;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

/**
 * (GroupInfo)表服务实现类
 *
 * @author makejava
 * @since 2024-10-08 19:54:21
 */
@Service("groupInfoService")
public class GroupInfoServiceImpl implements GroupInfoService {
    @Resource
    private GroupInfoDao groupInfoDao;
    @Resource
    private RedisComponent redisComponent;
    @Resource
    private UserContactDao userContactDao;
    @Resource
    private AppConfig appConfig;
    @Resource
    private ChatSessionDao chatSessionDao;
    @Resource
    private ChatSessionUserDao chatSessionUserDao;
    @Resource
    private ChannelContextUtils channelContextUtils;
    @Resource
    private ChatMessageDao chatMessageDao;
    @Resource
    private MessageHandler messageHandler;
    @Resource
    private UserContactApplyService userContactApplyService;
    @Resource
    private UserInfoDao userInfoDao;
    @Resource
    @Lazy
    private GroupInfoService groupInfoService;

    /**
     * 通过ID查询单条数据
     *
     * @param groupId 主键
     * @return 实例对象
     */
    @Override
    public GroupInfo queryById(String groupId) {
        return this.groupInfoDao.queryById(groupId);
    }

    /**
     * 分页查询
     *
     * @param userId 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public PageResult queryByPage(String userId, PageRequest pageRequest) {
        long total = this.groupInfoDao.count(userId);
        PageHelper.startPage(pageRequest.getPageNumber(),pageRequest.getPageSize());
        List<GroupInfo> groupInfoList = groupInfoDao.queryAllByLimit(userId);
        PageResult pageResult = new PageResult(total, groupInfoList);
        return pageResult;
    }

    /**
     * 新增数据
     *
     * @param groupInfoDto 实例对象
     * @return 实例对象
     */
    @Override
    public Boolean insert(GroupInfoDto groupInfoDto) {
        int insert = this.groupInfoDao.insert(groupInfoDto);
        if (insert>0){

            return true;
        }
        return false;
    }

    /**
     * 修改数据
     *
     * @param groupInfo 实例对象
     * @return 实例对象
     */
    @Override
    public GroupInfo update(GroupInfo groupInfo) {
        this.groupInfoDao.update(groupInfo);
        return this.queryById(groupInfo.getGroupId());
    }

    /**
     * 通过主键删除数据
     *
     * @param groupId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String groupId) {
        return this.groupInfoDao.deleteById(groupId) > 0;
    }

    /**
     * 创建群组
     * @param groupInfo
     * @param avatarCover
     * @param avatarFile
     * @return
     */
    @Override
    @Transactional
    public void saveGroup(GroupInfoDto groupInfo, MultipartFile avatarCover, MultipartFile avatarFile) throws IOException {
        Date curDate = new Date();
        //新增
        if (StringTools.isEmpty(groupInfo.getGroupId())){
            //查看当前用户创建群的个数
            Integer count = groupInfoDao.selectCount(groupInfo.getGroupOwnerId());
            SysSettingDto sysSetting = redisComponent.getSysSetting();
            if(count>=sysSetting.getMaxGroupCount()){
                throw new LeaseException("最多只能创建"+sysSetting.getMaxGroupCount()+"个群聊" , 606);
            }
            if(null == avatarFile){
                throw new LeaseException("图片未上传错误");
            }
            groupInfo.setCreateTime(curDate);
            groupInfo.setGroupId(StringTools.getGroupId());
            this.groupInfoDao.insert(groupInfo);

            //将群组添加为联系人
            UserContact userContact = new UserContact();
            userContact.setStatus(1);
            userContact.setContactType(1);
            userContact.setContactId(groupInfo.getGroupId());
            userContact.setUserId(groupInfo.getGroupOwnerId());
            userContact.setCreateTime(curDate);
            userContact.setLastUpdateTime(curDate);
            userContactDao.insert(userContact);

            //创建会话
            String sessionId = StringTools.getChatSessionId4Group(groupInfo.getGroupId());
            ChatSession chatSession = new ChatSession();
            chatSession.setSessionId(sessionId);
            chatSession.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatSession.setLastReceiveTime(curDate.getTime());
            chatSessionDao.insertOrUpdate(chatSession);

            ChatSessionUser chatSessionUser = new ChatSessionUser();
            chatSessionUser.setUserId(groupInfo.getGroupOwnerId());
            chatSessionUser.setContactId(groupInfo.getGroupId());
            chatSessionUser.setContactName(groupInfo.getGroupName());
            chatSessionUser.setSessionId(sessionId);
            chatSessionUserDao.insert(chatSessionUser);

            //创建消息
            ChatMessage chatMessage = new ChatMessage();
            chatMessage.setSessionId(sessionId);
            chatMessage.setMessageType(MessageTypeEnum.GROUP_CREATE.getType());
            chatMessage.setMessageContent(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatMessage.setSendTime(curDate.getTime());
            chatMessage.setContactType(UserContactTypeEnum.GROUP.getType());
            chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
            chatMessageDao.insert(chatMessage);

            //将群组添加到联系人
            redisComponent.addUserContact(groupInfo.getGroupOwnerId(), groupInfo.getGroupId());
            //将联系人的channel添加到群组channel
            channelContextUtils.addUser2Group(groupInfo.getGroupOwnerId(),groupInfo.getGroupId());

            //发送ws消息
            chatSessionUser.setLastMessage(MessageTypeEnum.GROUP_CREATE.getInitMessage());
            chatSessionUser.setLastReceiveTime(curDate.getTime());
            //获取群人数
            chatSessionUser.setMemberCount(1);

            MessageSendDto messageSendDto = new MessageSendDto();
            BeanUtils.copyProperties(chatMessage,messageSendDto);
            messageSendDto.setExtendData(chatSessionUser);
            messageSendDto.setLastMessage(chatSessionUser.lastMessage);

            messageHandler.sendMessage(messageSendDto);


        }else {
            //修改群组信息
            GroupInfo dbInfo = groupInfoDao.selectByGroupId(groupInfo.getGroupId());
            if(!dbInfo.getGroupOwnerId().equals(groupInfo.getGroupOwnerId())){
                throw new LeaseException("输入信息错误...",409);
            }
            dbInfo = new GroupInfo();
            BeanUtils.copyProperties(groupInfo,dbInfo);
            groupInfoDao.update(dbInfo);

            //更新相关表冗余信息
            String contactNameUpdate =  null;
            if(!dbInfo.getGroupName().equals(groupInfo.getGroupName())){
                contactNameUpdate = groupInfo.getGroupName();
            }
            if(contactNameUpdate == null) {
                return;
            }

            ChatSessionUser updateInfo = new ChatSessionUser();
            updateInfo.setContactName(groupInfo.getGroupName());
            updateInfo.setContactId(groupInfo.getGroupId());
            chatSessionUserDao.update(updateInfo);

            //修改群昵称发送ws消息
            MessageSendDto messageSendDto = new MessageSendDto();
            messageSendDto.setContactType(UserContactTypeEnum.GROUP.getType());
            messageSendDto.setContactId(groupInfo.getGroupId());
            messageSendDto.setExtendData(contactNameUpdate);
            messageSendDto.setMessageType(MessageTypeEnum.GROUP_NAME_UPDATE.getType());
            messageHandler.sendMessage(messageSendDto);


        }
        if(null == avatarFile){
            return;
        }
        String baseFolder = appConfig.getProjectFolder() + Constants.FILE_FOLDER_FILE;
        File targetFileFolder = new File(baseFolder + Constants.FILE_FOLDER_AVATAR_NAME);
        //目录不存在就创建
        if(!targetFileFolder.exists()){
            targetFileFolder.mkdirs();
        }
        String filePath = targetFileFolder.getPath() + "/" +groupInfo.getGroupId() + Constants.IMAGE_SUFFIX;
        avatarFile.transferTo(new File(filePath));
        avatarCover.transferTo(new File(filePath+ Constants.COVER_IMAGE_SUFFIX));

    }

    @Override
    public GroupInfo getGroupInfoByGroupId(String groupId, String userId) {
        GroupInfo groupInfo = groupInfoDao.selectByGroupIdAndUserId(groupId,userId);
        return groupInfo;
    }

    @Override
    public PageResult findListByPage(GroupInfoQuery query) {
        PageHelper.startPage(query.getPageNumber(), query.getPageSize());
        PageHelper.orderBy(query.getOrderBy());
        GroupInfo groupInfo = new GroupInfo();
        BeanUtils.copyProperties(query,groupInfo);
        List<GroupInfoVO> list = groupInfoDao.selectPage(groupInfo);
        Integer count = groupInfoDao.adminCount(groupInfo);
        PageResult pageResult = new PageResult(count, list);
        return pageResult;
    }

    @Override
    @Transactional
    public void dissolutionGroup(String groupId, String groupOwnerId) {
        GroupInfo dbInfo = groupInfoDao.selectByGroupId(groupId);
        if(dbInfo == null || !dbInfo.getGroupOwnerId().equals(groupOwnerId)){
              throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        //删除群组
        GroupInfo updateInfo = new GroupInfo();
        updateInfo.setStatus(0);
        groupInfoDao.update(updateInfo);

        //更新联系人信息
        UserContactQuery userContactQuery = new UserContactQuery();
        userContactQuery.setContactId(groupId);
        userContactQuery.setContactType(UserContactTypeEnum.GROUP.getType());

        UserContact updateUserContact = new UserContact();
        updateUserContact.setStatus(2);
        userContactDao.updateByParam(updateUserContact,userContactQuery);

        //移出相关群员的联系人缓存
        List<UserContact> userContactList = userContactDao.selectList(userContactQuery);
        //删除群组成员
        for(UserContact userContact:userContactList){
            redisComponent.removeUserContact(userContact.getUserId(),userContact.getContactId());
        }
        String sessionId = StringTools.getChatSessionId4Group(groupId);
        Date curDate = new Date();
        String messageContent = MessageTypeEnum.DISSOLUTION_GROUP.getInitMessage();

        //更新会话
        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(messageContent);
        chatSession.setLastReceiveTime(curDate.getTime());
        chatSession.setSessionId(sessionId);
        chatSessionDao.update(chatSession);

        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setSessionId(sessionId);
        chatMessage.setSendTime(curDate.getTime());
        chatMessage.setContactType(UserContactTypeEnum.GROUP.getType());
        chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessage.setMessageType(MessageTypeEnum.DISSOLUTION_GROUP.getType());
        chatMessage.setContactId(groupId);
        chatMessage.setMessageContent(messageContent);
        chatMessageDao.insert(chatMessage);

        MessageSendDto messageSendDto = new MessageSendDto();
        BeanUtils.copyProperties(chatMessage,messageSendDto);
        messageHandler.sendMessage(messageSendDto);

    }

    /**
     * 添加或删除群成员
     * @param tokenUserInfoDto
     * @param groupId
     * @param contactIds
     * @param opType
     */

    @Override
    public void addOrRemoveGroupUser(TokenUserInfoDto tokenUserInfoDto, String groupId, String contactIds, Integer opType) {
        GroupInfo groupInfo = groupInfoDao.selectByGroupId(groupId);
        if(null== groupInfo || groupInfo.getGroupOwnerId().equals(tokenUserInfoDto.getUserId())){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        String[] contactIdList = contactIds.split(",");
        for (String contactId : contactIdList){
            if(0==opType){
                groupInfoService.leaveGroup(contactId,groupId,MessageTypeEnum.REMOVE_GROUP);
            }else {
                userContactApplyService.addContact(contactId,null,groupId,UserContactTypeEnum.GROUP.getType(),null);
            }
        }

    }

    /**
     * 移出/退出群聊
     * @param userId
     * @param groupId
     * @param messageTypeEnum
     */
    @Override//类的内部调用，会导致事务失效；因为没有使用到spring管理的bean
    @Transactional(rollbackFor = Exception.class)
    public void leaveGroup(String userId, String groupId, MessageTypeEnum messageTypeEnum) {
        GroupInfo groupInfo = groupInfoDao.selectByGroupId(groupId);
        if(groupInfo==null){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        if(userId.equals(groupInfo.getGroupOwnerId())){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        Integer count =userContactDao.deleteByUserIdAndContactId(userId,groupId);
        if(count==0){
            throw new LeaseException(ExceptionCodeEnum.ERROR_REQUEST);
        }
        UserInfo userInfo = userInfoDao.queryById(userId);

        String sessionId = StringTools.getChatSessionId4Group(groupId);
        Date curDate = new Date();
        String messageContent = String.format(messageTypeEnum.getInitMessage(),userInfo.getNickName());

        ChatSession chatSession = new ChatSession();
        chatSession.setLastMessage(messageContent);
        chatSession.setLastReceiveTime(curDate.getTime());
        chatSessionDao.update(chatSession);

        ChatMessage chatMessage = new ChatMessage();
        chatMessage.setSessionId(sessionId);
        chatMessage.setMessageContent(messageContent);
        chatMessage.setSendTime(curDate.getTime());
        chatMessage.setContactType(UserContactTypeEnum.GROUP.getType());
        chatMessage.setStatus(MessageStatusEnum.SENDED.getStatus());
        chatMessage.setContactId(groupId);
        chatMessageDao.insert(chatMessage);

        Integer memberCount = userContactDao.selectCount(groupId, UserContactTypeEnum.GROUP.getType());
        MessageSendDto messageSendDto = new MessageSendDto();
        BeanUtils.copyProperties(chatMessage,messageSendDto);

        messageSendDto.setExtendData(userId);
        messageSendDto.setMemberCount(memberCount);
        messageHandler.sendMessage(messageSendDto);


    }
}
